package com.ifinc.common.utils.sec;


import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.util.io.Streams;

import java.io.*;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Iterator;

/**
 * User: luotao
 * Date: 13-11-18
 * Time: 13:07
 */
public class PGPUtils {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static void decryptFile(File inputFile,
                                   String keyFileName,
                                   char[] passwd,
                                   String defaultFileName)
            throws IOException, NoSuchProviderException {
        InputStream in = new BufferedInputStream(new FileInputStream(inputFile));
        InputStream keyIn = new BufferedInputStream(new FileInputStream(keyFileName));
        decryptFile(in, keyIn, passwd, defaultFileName);
        keyIn.close();
        in.close();
    }

    public static void decryptFile(
            String inputFileName,
            String keyFileName,
            char[] passwd,
            String defaultFileName)
            throws IOException, NoSuchProviderException {
        InputStream in = new BufferedInputStream(new FileInputStream(inputFileName));
        InputStream keyIn = new BufferedInputStream(new FileInputStream(keyFileName));
        decryptFile(in, keyIn, passwd, defaultFileName);
        keyIn.close();
        in.close();
    }

    /**
     * decrypt the passed in message stream
     */
    private static void decryptFile(
            InputStream in,
            InputStream keyIn,
            char[] passwd,
            String defaultFileName)
            throws IOException, NoSuchProviderException {
        in = PGPUtil.getDecoderStream(in);

        try {
            PGPObjectFactory pgpF = new PGPObjectFactory(in);
            PGPEncryptedDataList enc;

            Object o = pgpF.nextObject();
            //
            // the first object might be a PGP marker packet.
            //
            if (o instanceof PGPEncryptedDataList) {
                enc = (PGPEncryptedDataList) o;
            } else {
                enc = (PGPEncryptedDataList) pgpF.nextObject();
            }

            //
            // find the secret key
            //
            Iterator it = enc.getEncryptedDataObjects();
            PGPPrivateKey sKey = null;
            PGPPublicKeyEncryptedData pbe = null;
            PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
                    PGPUtil.getDecoderStream(keyIn));

            while (sKey == null && it.hasNext()) {
                pbe = (PGPPublicKeyEncryptedData) it.next();

                sKey = PGPExampleUtil.findSecretKey(pgpSec, pbe.getKeyID(), passwd);
            }

            if (sKey == null) {
                throw new IllegalArgumentException("secret key for message not found.");
            }

            InputStream clear = pbe.getDataStream(sKey, "BC");

            PGPObjectFactory plainFact = new PGPObjectFactory(clear);

            Object message = plainFact.nextObject();

            if (message instanceof PGPCompressedData) {
                PGPCompressedData cData = (PGPCompressedData) message;
                PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream());

                message = pgpFact.nextObject();
            }

            if (message instanceof PGPLiteralData) {
                PGPLiteralData ld = (PGPLiteralData) message;

                String outFileName = ld.getFileName();
                if (outFileName.length() == 0) {
                    outFileName = defaultFileName;
                }

                InputStream unc = ld.getInputStream();
                OutputStream fOut = new BufferedOutputStream(new FileOutputStream(defaultFileName));

                Streams.pipeAll(unc, fOut);

                fOut.close();
            } else if (message instanceof PGPOnePassSignatureList) {
                throw new PGPException("encrypted message contains a signed message - not literal data.");
            } else {
                throw new PGPException("message is not a simple encrypted file - type unknown.");
            }

            if (pbe.isIntegrityProtected()) {
                if (!pbe.verify()) {
                    System.err.println("message failed integrity check");
                } else {
                    System.err.println("message integrity check passed");
                }
            } else {
                System.err.println("no message integrity check");
            }
        } catch (PGPException e) {
            System.err.println(e);
            if (e.getUnderlyingException() != null) {
                e.getUnderlyingException().printStackTrace();
            }
        }
    }

    public static void encryptFile(
            String outputFileName,
            String inputFileName,
            String encKeyFileName,
            boolean armor,
            boolean withIntegrityCheck)
            throws IOException, NoSuchProviderException, PGPException {
        OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFileName));
        PGPPublicKey encKey = PGPExampleUtil.readPublicKey(encKeyFileName);
        encryptFile(out, inputFileName, encKey, armor, withIntegrityCheck);
        out.close();
    }

    private static void encryptFile(
            OutputStream out,
            String fileName,
            PGPPublicKey encKey,
            boolean armor,
            boolean withIntegrityCheck)
            throws IOException, NoSuchProviderException {
        if (armor) {
            out = new ArmoredOutputStream(out);
        }

        try {
            byte[] bytes = PGPExampleUtil.compressFile(fileName, CompressionAlgorithmTags.ZIP);

            PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
                    PGPEncryptedData.CAST5, withIntegrityCheck, new SecureRandom(), "BC");
            encGen.addMethod(encKey);

            OutputStream cOut = encGen.open(out, bytes.length);

            cOut.write(bytes);
            cOut.close();

            if (armor) {
                out.close();
            }
        } catch (PGPException e) {
            System.err.println(e);
            if (e.getUnderlyingException() != null) {
                e.getUnderlyingException().printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
//        String inputFile = "E:\\project\\work\\bank\\bank-check\\bank-check-core\\src\\main\\java\\com\\wangyin\\bank\\check\\core\\security\\gpg\\src.txt";
//        String outFile = "E:\\project\\work\\bank\\bank-check\\bank-check-core\\src\\main\\java\\com\\wangyin\\bank\\check\\core\\security\\gpg\\src.txt.gpg";
//        String keyFile = "E:\\project\\bc\\bcpg-jdk15on-149\\src\\org\\bouncycastle\\openpgp\\examples\\test\\hello_pub.asc";
//        encryptFile(outFile, inputFile, keyFile, false, false);


//        String secKeyFile = "E:\\project\\bc\\bcpg-jdk15on-149\\src\\org\\bouncycastle\\openpgp\\examples\\test\\hello_pri.asc";
//        String password = "123456";
//        String plainFile = "E:\\project\\work\\bank\\bank-check\\bank-check-core\\src\\main\\java\\com\\wangyin\\bank\\check\\core\\security\\gpg\\src_result.txt";
//        decryptFile(outFile, secKeyFile, password.toCharArray(), plainFile);
//        String inputFile1 = "E:\\project\\work\\bank\\bank-check\\bank-check-resolver\\src\\main\\java\\com\\wangyin\\bank\\check\\resolver\\security\\zdz_wyzx_20121026.txt.pgp";
//        String secKeyFile = "e:\\test.asc";
//        String password = "ningtao";
//        String plainFile = "E:\\project\\work\\bank\\bank-check\\bank-check-resolver\\src\\main\\java\\com\\wangyin\\bank\\check\\resolver\\security\\boc_result.txt.gz";
//        decryptFile(inputFile1, secKeyFile, password.toCharArray(), plainFile);


//        File signFile = new File("E:\\project\\work\\bank\\bank-check\\bank-check-resolver\\src\\main\\java\\com\\wangyin\\bank\\check\\resolver\\security\\signature.sgn.20111119");
//        File signKeyFile = new File("E:\\project\\work\\bank\\bank-check\\bank-check-resolver\\src\\main\\java\\com\\wangyin\\bank\\check\\resolver\\security\\zdz_wyzx_20121026.txt.pgp");
//        FileInputStream signInputStream = FileUtils.openInputStream(signFile);
//        FileInputStream  signKeyInputStream = FileUtils.openInputStream(signKeyFile);
//        verifyFile(signInputStream,signKeyInputStream);
//
//        Money money = new Money("0.006");
//        long amount = money.getCent();
//        System.out.println("amount = " + amount);
    }
}
